﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
using System.Text;
using System.IO;
using System.Globalization;
using SpLocalizer.Common;
using SpLocalizer.Common.DbApi;

namespace SpLocalizer.ContentSourceProviders.XPath
{
    public class WebPartFileContent : XPathContent
    {
        private const string StartPattern = "<?xml";
        private const string EndPattern = "</WebPartDefinition>";

        private const string CdataStartPattern = "<![CDATA[";
        private const string CdataEndPattern = "]]>";

        private bool isValidXml{get;set;}

        private XmlNamespaceManager NamespaceManager{
            get
            {
                XmlNamespaceManager manager = new XmlNamespaceManager(XPathNav.NameTable);
                manager.AddNamespace("v2", "http://schemas.microsoft.com/WebPart/v2");
                manager.AddNamespace("v3", "http://schemas.microsoft.com/WebPart/v3");
                manager.AddNamespace("c", "http://schemas.microsoft.com/WebPart/v2/ContentEditor");

                return manager;
            }
          }

        public WebPartFileContent(string[] XPath) : base(XPath) { }

        public override void Bind(string XmlFilePath)
        {
            this.XmlDoc = new XmlDocument();
            this.XmlDoc.PreserveWhitespace = true;
            XmlSchema schema = new XmlSchema();         

            schema.Namespaces.Add("xsd", "http://www.w3.org/2001/XMLSchema");
            schema.Namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
            

            this.XmlDoc.Schemas.Add(schema);

            try
            {
                this.XmlDoc.Load(XmlFilePath);
                this.isValidXml = true;
            }
            catch (System.Xml.XmlException)
            {                
                XmlDeclaration dec = this.XmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
                this.XmlDoc.AppendChild(dec);             
                this.LoadWebPartFileXml(XmlFilePath);
                this.isValidXml = false;
            }
            

            this.ContentAddress = XmlFilePath;
        }


        private void LoadWebPartFileXml(string PageFilePath)
        {
            string PageContent = File.ReadAllText(PageFilePath);
            int StartIndex = PageContent.IndexOf(StartPattern);
            if (StartIndex < 0)
                return; // This is not a Publishsing page
            int EndIndex = PageContent.IndexOf(EndPattern) - StartIndex;

            PageContent = PageContent.Substring(StartIndex, EndIndex);

            this.XmlDoc.LoadXml(PageContent);
        }

        public override IEnumerable<BaseTranslationTask> BuildTranslationTasks(CultureInfo FromLanguage, CultureInfo ToLanguage)
        {
            // Select all book nodes that have the matching attribute value.
            List<BaseTranslationTask> tasksToTranslate = new List<BaseTranslationTask>();

          

            foreach (string xPathString in XPath)
            {
                XPathNodeIterator ni = XPathNav.Select(xPathString, this.NamespaceManager);
                while (ni.MoveNext())
                {
                    if (ni.Current != null && !string.IsNullOrEmpty(ni.Current.Value) && !string.IsNullOrEmpty(ni.Current.Value.Trim()))
                    {
                        XPathContentLocalizationTask tt = new XPathContentLocalizationTask(FromLanguage, ToLanguage,
                            xPathString, ni.CurrentPosition);
                        tt.SourceText = ni.Current.Value;
                        tt.Status = TranslationTaskStatus.Initialized;
                        tt.Format = isTaskContainHtml(tt) ? Constants.TASK_FORMAT_HTML : Constants.TASK_FORMAT_TEXT;
                        tasksToTranslate.Add(tt);
                    }
                }
            }


            return tasksToTranslate;
        }

        public override void ExportContentTranslations(BaseTranslationTask TranslationTask)
        {
            if (this.isValidXml)
            {
                TaskLanguage = TranslationTask.ToLanguage.Name; // Set language name from tasks

                XPathNodeIterator iterator = XPathNav.Select(((XPathContentLocalizationTask)TranslationTask).XPath, this.NamespaceManager);
                int NodeIndex = int.Parse(((XPathContentLocalizationTask)TranslationTask).Position);

                while (iterator.CurrentPosition < NodeIndex) // Position Navigator
                    iterator.MoveNext();

                // check if source text the same
                if (!TranslationTask.SourceText.Equals(iterator.Current.Value))
                    throw new ApplicationException(String.Format("URI: {0} source text:\n {1} \n doesnt match database source:\n {2}",
                        iterator.Current.BaseURI, iterator.Current.Value, TranslationTask.SourceText));
             
                    iterator.Current.SetValue(TranslationTask.TranslatedText);
                
            }
            else
            {
                XmlNodeList nodes = this.XmlDoc.SelectNodes(((XPathContentLocalizationTask)TranslationTask).XPath, this.NamespaceManager);
                if (nodes.Count != 1)
                    throw new ApplicationException(String.Format("Illegal count of nodes {0}, for task id {1} in the file {2}", nodes.Count, TranslationTask.TaskId, this.ContentAddress));

                XmlNode node = nodes[0];

                // check if source text the same
                if (!TranslationTask.SourceText.Equals(node.InnerText))
                    throw new ApplicationException(String.Format("URI: {0} source text:\n {1} \n doesnt match database source:\n {2}",
                        node.BaseURI, node.InnerText, TranslationTask.SourceText));

                if (node.InnerXml.StartsWith(CdataStartPattern))
                {
                    XmlCDataSection cdata = this.XmlDoc.CreateCDataSection(TranslationTask.TranslatedText);
                    node.ReplaceChild(cdata, node.FirstChild);
                   // node.InnerText = cdata.InnerText;
                        //.WriteContentTo(writer.WriteCData(TranslationTask.TranslatedText);
                }
                else
                    node.InnerText = TranslationTask.TranslatedText;
            }

            //
        }


        public override void PerformExportDone()
        {
            if (this.isValidXml)
            {
                base.PerformExportDone();
                return;
            }
            else
            {
                FileInfo fi = new FileInfo(this.ContentAddress);
                DirectoryInfo dir = fi.Directory; //.CreateSubdirectory(this.TaskLanguage);

                StringBuilder result = new StringBuilder();

                using (XmlWriter xw = XmlWriter.Create(result))
                {
                    XmlDoc.WriteTo(xw);
                }


                string PageContent = File.ReadAllText(this.ContentAddress);

                int StartIndex = PageContent.IndexOf(StartPattern);
                int EndIndex = PageContent.IndexOf(EndPattern);
                result.Insert(0, PageContent.Substring(0, StartIndex));
                result.Append(PageContent.Substring(EndIndex, PageContent.Length - EndIndex));

                File.WriteAllText(dir.FullName + "\\" + fi.Name, result.ToString());
            }
        }
    }
}
